/**
 * 信效度计算工具
 * 用于计算问卷的信度和效度
 */

class ReliabilityCalculator {
    /**
     * 初始化问卷信息
     * @param {Array<Object>} questions - 问题数组，每个问题包含类型、选项等信息
     */
    static initializeQuestionnaire(questions) {
        if (!window.questionnaireInfo) {
            console.error('问卷信息对象未定义');
            return;
        }
        window.questionnaireInfo.questions = questions.map(q => ({
            type: q.type,
            optionsCount: q.options ? q.options.length : 0,
            isSingleChoice: q.type === 'SINGLE_CHOICE'
        }));
        window.questionnaireInfo.initialized = true;
        console.log('问卷信息初始化完成:', window.questionnaireInfo);
    }

    /**
     * 计算Cronbach's Alpha系数
     * @param {Array<Array<number>>} data - 二维数组，每行代表一个被试，每列代表一个题目
     * @returns {number} - Cronbach's Alpha系数
     */
    static calculateCronbachAlpha(data) {
        console.log('进入calculateCronbachAlpha方法');
        console.log('输入数据:', data);
        
        if (!data || data.length === 0) {
            console.log('数据为空，返回0');
            return 0;
        }
        
        const n = data[0].length; // 题目数量
        const respondents = data.length; // 被试数量
        
        console.log('题目数量:', n);
        console.log('被试数量:', respondents);
        
        if (n <= 1) {
            console.log('题目数量不足，返回0');
            return 0;
        }

        // 计算每个被试的总分
        const totalScores = data.map(row => 
            row.reduce((sum, score) => sum + score, 0)
        );
        console.log('总分:', totalScores);

        // 计算总分方差
        const totalMean = totalScores.reduce((sum, score) => sum + score, 0) / respondents;
        const totalVariance = totalScores.reduce((sum, score) => 
            sum + Math.pow(score - totalMean, 2), 0) / (respondents - 1); // 使用无偏估计
        console.log('总分均值:', totalMean);
        console.log('总分方差:', totalVariance);

        // 计算各题目得分方差之和和题目间相关系数
        let sumOfItemVariances = 0;
        const itemMeans = new Array(n).fill(0);
        const itemVariances = new Array(n).fill(0);
        
        // 先计算每个题目的均值和方差
        for (let j = 0; j < n; j++) {
            const scores = data.map(row => row[j]);
            itemMeans[j] = scores.reduce((sum, score) => sum + score, 0) / respondents;
            itemVariances[j] = scores.reduce((sum, score) => 
                sum + Math.pow(score - itemMeans[j], 2), 0) / (respondents - 1);
            sumOfItemVariances += itemVariances[j];
        }
        
        // 计算题目间的相关系数矩阵
        const correlationMatrix = Array(n).fill().map(() => Array(n).fill(0));
        let sumCorrelation = 0;
        let correlationCount = 0;

        for (let i = 0; i < n; i++) {
            correlationMatrix[i][i] = 1; // 对角线上的相关系数为1
            for (let j = i + 1; j < n; j++) {
                const scoresI = data.map(row => row[i]);
                const scoresJ = data.map(row => row[j]);
                const correlation = this.calculatePearsonCorrelation(scoresI, scoresJ);
                
                correlationMatrix[i][j] = correlation;
                correlationMatrix[j][i] = correlation; // 相关矩阵是对称的
                
                sumCorrelation += correlation;
                correlationCount++;
            }
        }
        
        console.log('题目均值:', itemMeans);
        console.log('题目方差:', itemVariances);
        console.log('题目方差之和:', sumOfItemVariances);
        console.log('题目间相关系数矩阵:', correlationMatrix);

        // 计算平均题目间相关系数
        const avgCorrelation = correlationCount > 0 ? sumCorrelation / correlationCount : 0;
        console.log('平均题目间相关系数:', avgCorrelation);

        // 计算Cronbach's Alpha
        // α = [k/(k-1)] * [1 - (∑σ²(i))/(σ²x)]
        const alpha = (n / (n - 1)) * (1 - (sumOfItemVariances / totalVariance));
        console.log('计算得到的alpha值:', alpha);

        // 返回实际的alpha值，包括负值
        return alpha;
    }
    
    /**
     * 计算方差
     * @param {Array<number>} data - 数据数组
     * @returns {number} - 方差
     */
    static calculateVariance(data) {
        const mean = data.reduce((sum, val) => sum + val, 0) / data.length;
        const squaredDifferences = data.map(val => Math.pow(val - mean, 2));
        return squaredDifferences.reduce((sum, val) => sum + val, 0) / data.length;
    }
    
    /**
     * 计算折半信度
     * @param {Array<Array<number>>} data - 二维数组，每行代表一个被试，每列代表一个题目
     * @returns {number} - 折半信度系数
     */
    static calculateSplitHalfReliability(data) {
        if (!data || data.length === 0) return 0;
        
        const n = data[0].length; // 题目数量
        if (n <= 1) return 0; // 至少需要两个题目
        
        // 将题目分为两半
        const firstHalf = [];
        const secondHalf = [];
        
        for (let i = 0; i < data.length; i++) {
            const row = data[i];
            const firstHalfRow = [];
            const secondHalfRow = [];
            
            for (let j = 0; j < row.length; j++) {
                if (j % 2 === 0) {
                    firstHalfRow.push(row[j]);
                } else {
                    secondHalfRow.push(row[j]);
                }
            }
            
            firstHalf.push(firstHalfRow);
            secondHalf.push(secondHalfRow);
        }
        
        // 计算两半的总分
        const firstHalfScores = firstHalf.map(row => row.reduce((sum, score) => sum + score, 0));
        const secondHalfScores = secondHalf.map(row => row.reduce((sum, score) => sum + score, 0));
        
        // 计算两半之间的相关系数
        const correlation = this.calculatePearsonCorrelation(firstHalfScores, secondHalfScores);
        
        // 使用Spearman-Brown公式校正
        const reliability = (2 * correlation) / (1 + correlation);
        
        return reliability;
    }
    
    /**
     * 计算Pearson相关系数
     * @param {Array<number>} x - 第一组数据
     * @param {Array<number>} y - 第二组数据
     * @returns {number} - 相关系数
     */
    static calculatePearsonCorrelation(x, y) {
        if (x.length !== y.length || x.length === 0) return 0;
        
        const n = x.length;
        
        // 计算均值
        const meanX = x.reduce((sum, val) => sum + val, 0) / n;
        const meanY = y.reduce((sum, val) => sum + val, 0) / n;
        
        // 计算协方差和标准差
        let covariance = 0;
        let varX = 0;
        let varY = 0;
        
        for (let i = 0; i < n; i++) {
            const diffX = x[i] - meanX;
            const diffY = y[i] - meanY;
            covariance += diffX * diffY;
            varX += diffX * diffX;
            varY += diffY * diffY;
        }
        
        covariance /= n;
        varX /= n;
        varY /= n;
        
        const stdX = Math.sqrt(varX);
        const stdY = Math.sqrt(varY);
        
        // 避免除以零
        if (stdX === 0 || stdY === 0) return 0;
        
        return covariance / (stdX * stdY);
    }
    
    /**
     * 生成模拟数据用于信效度计算
     * @param {number} numRespondents - 被试数量
     * @param {number} numQuestions - 题目数量
     * @param {number} reliability - 期望的信度系数 (0-1)
     * @returns {Array<Array<number>>} - 生成的数据
     */
    static generateSimulatedData(numRespondents, numQuestions, reliability = 0.8) {
        const data = [];
        
        // 生成一个潜在特质值作为真实分数
        const trueScores = Array(numRespondents).fill(0).map(() => Math.random());
        
        // 根据期望的信度系数确定误差方差
        const errorVariance = (1 - reliability) / reliability;
        
        for (let i = 0; i < numRespondents; i++) {
            const row = [];
            const trueScore = trueScores[i];
            
            for (let j = 0; j < numQuestions; j++) {
                // 添加随机误差
                const error = Math.sqrt(errorVariance) * (Math.random() - 0.5);
                // 将分数映射到1-5的范围
                let score = Math.round((trueScore + error) * 4 + 1);
                // 确保分数在有效范围内
                score = Math.max(1, Math.min(5, score));
                row.push(score);
            }
            
            data.push(row);
        }
        
        return data;
    }
    
    /**
     * 从问卷选项百分比生成模拟数据
     * @param {Array<Object>} questions - 问题数组，每个问题包含选项及其百分比
     * @param {number} numRespondents - 模拟的被试数量
     * @returns {Array<Array<number>>} - 生成的数据
     */
    static generateDataFromPercentages(questions, numRespondents) {
        const data = [];
        
        // 为每个被试生成答案
        for (let i = 0; i < numRespondents; i++) {
            const row = [];
            
            // 对每个问题
            for (const question of questions) {
                const options = question.options;
                const percentages = options.map(option => option.percentage / 100);
                
                // 根据百分比随机选择一个选项
                const randomValue = Math.random();
                let cumulativeProb = 0;
                let selectedOption = 0;
                
                for (let j = 0; j < percentages.length; j++) {
                    cumulativeProb += percentages[j];
                    if (randomValue <= cumulativeProb) {
                        selectedOption = j + 1; // 选项从1开始计数
                        break;
                    }
                }
                
                // 如果由于舍入误差没有选择任何选项，选择最后一个
                if (selectedOption === 0) {
                    selectedOption = percentages.length;
                }
                
                row.push(selectedOption);
            }
            
            data.push(row);
        }
        
        return data;
    }

    /**
     * 计算校正的项总计相关性(CITC)
     * @param {Array<Array<number>>} data - 二维数组，每行代表一个被试，每列代表一个题目
     * @returns {Array<number>} - 每个题目的CITC值
     */
    static calculateCITC(data) {
        if (!data || data.length === 0) return [];
        
        const n = data[0].length; // 题目数量
        const respondents = data.length; // 被试数量
        const citcValues = new Array(n).fill(0);
        
        for (let currentItem = 0; currentItem < n; currentItem++) {
            // 计算总分（不包括当前题目）
            const otherItemsTotal = data.map(row => 
                row.reduce((sum, score, index) => 
                    index !== currentItem ? sum + score : sum, 0)
            );
            
            // 计算当前题目与其他题目总分的相关系数
            const currentItemScores = data.map(row => row[currentItem]);
            citcValues[currentItem] = this.calculatePearsonCorrelation(
                currentItemScores,
                otherItemsTotal
            );
        }
        
        return citcValues;
    }

    /**
     * 计算项已删除的α系数
     * @param {Array<Array<number>>} data - 二维数组，每行代表一个被试，每列代表一个题目
     * @returns {Array<number>} - 每个题目删除后的α系数
     */
    static calculateAlphaIfItemDeleted(data) {
        if (!data || data.length === 0) return [];
        
        const n = data[0].length; // 题目数量
        const alphaValues = new Array(n).fill(0);
        
        for (let itemToDelete = 0; itemToDelete < n; itemToDelete++) {
            // 创建删除当前题目后的新数据集
            const reducedData = data.map(row => 
                row.filter((_, index) => index !== itemToDelete)
            );
            
            // 计算删除该题目后的α系数
            alphaValues[itemToDelete] = this.calculateCronbachAlpha(reducedData);
        }
        
        return alphaValues;
    }

    /**
     * 从问卷选项百分比生成确定性数据（优化版）
     * @param {Array<Object>} questions - 问题数组，每个问题包含选项及其百分比
     * @param {number} numRespondents - 模拟的被试数量
     * @returns {Array<Array<number>>} - 生成的确定性数据
     */
    static generateDeterministicDataFromPercentages(questions, numRespondents) {
        console.log(`开始生成确定性数据，问题数量: ${questions.length}, 被试数量: ${numRespondents}`);
        
        // 过滤出单选题
        const singleChoiceQuestions = questions.filter(question => {
            return question.options && question.options.length > 0;
        });

        // 初始化数据矩阵
        const data = new Array(numRespondents).fill(null).map(() => 
            new Array(singleChoiceQuestions.length).fill(0));

        // 为每个题目生成答案
        singleChoiceQuestions.forEach((question, qIndex) => {
            const options = question.options;
            const percentages = options.map(option => option.percentage / 100);
            
            // 获取每个选项的自定义分值
            const scores = options.map(option => option.score || (option.optionIndex + 1));
            
            // 计算每个选项的精确回答数量
            const optionCounts = percentages.map(percentage => 
                Math.round(percentage * numRespondents)
            );
            
            // 处理舍入误差，确保总数等于numRespondents
            let total = optionCounts.reduce((sum, count) => sum + count, 0);
            if (total !== numRespondents) {
                // 找到百分比最高的选项进行调整
                const maxIndex = percentages.indexOf(Math.max(...percentages));
                optionCounts[maxIndex] += (numRespondents - total);
            }
            
            // 生成答案数组，使用自定义分值
            let currentRespondent = 0;
            optionCounts.forEach((count, optionIndex) => {
                const score = scores[optionIndex];
                // 直接按顺序分配分值，不进行随机打乱
                for (let i = 0; i < count; i++) {
                    data[currentRespondent][qIndex] = score;
                    currentRespondent++;
                }
            });
        });

        return data;
    }

    /**
     * 根据选项百分比生成单选题答案
     * @param {Array<number>} percentages - 选项百分比数组
     * @returns {number} - 选中的选项编号（从1开始）
     */
    static generateSingleChoiceAnswer(percentages) {
        const randomValue = Math.random();
        let cumulativeProb = 0;
        
        for (let j = 0; j < percentages.length; j++) {
            cumulativeProb += percentages[j];
            if (randomValue <= cumulativeProb) {
                return j + 1; // 选项从1开始计数
            }
        }
        
        // 如果由于舍入误差没有选择任何选项，选择最后一个
        return percentages.length;
    }

    /**
     * 直接从选项百分比计算Cronbach's α系数
     * @param {Array<Object>} questions - 问题数组，每个问题包含选项及其百分比
     * @returns {number} - Cronbach's α系数
     */
    static calculateCronbachAlphaFromPercentages(questions) {
        console.log('开始计算Cronbach\'s α系数');
        console.log('问题数量:', questions);
        if (!questions || questions.length < 2) return 0;
        
        // 计算每个题目的方差和期望值
        const itemStats = questions.map(question => {
            const percentages = question.options.map(option => option.percentage / 100);
            
            // 计算期望值（加权平均）
            const mean = percentages.reduce((sum, p, i) => sum + p * (i + 1), 0);
            
            // 计算方差
            const variance = percentages.reduce((sum, p, i) => sum + p * Math.pow((i + 1) - mean, 2), 0);
            
            return { mean, variance };
        });
        
        // 计算题目间的协方差
        const n = questions.length;
        let sumOfCovariances = 0;
        
        for (let i = 0; i < n; i++) {
            for (let j = i + 1; j < n; j++) {
                const meanI = itemStats[i].mean;
                const meanJ = itemStats[j].mean;
                const covariance = Math.sqrt(itemStats[i].variance * itemStats[j].variance);
                sumOfCovariances += 2 * covariance; // 乘2因为我们只计算了上三角矩阵
            }
        }
        
        // 计算总方差
        const totalVariance = itemStats.reduce((sum, stat) => sum + stat.variance, 0) + sumOfCovariances;
        
        // 计算所有题目方差的和
        const sumOfItemVariances = itemStats.reduce((sum, stat) => sum + stat.variance, 0);
        
        // 计算Cronbach's α
        const alpha = (n / (n - 1)) * (1 - (sumOfItemVariances / totalVariance));
        
        return alpha;
    }

    /**
     * 获取信度评价
     * @param {number} alpha - Cronbach's α系数
     * @returns {string} - 信度评价
     */
    static getReliabilityInterpretation(alpha) {
        if (alpha < 0) {
            return '信度异常（存在负相关或需要反向计分）';
        }
        if (alpha >= 0.9) return '信度优秀';
        if (alpha >= 0.8) return '信度良好';
        if (alpha >= 0.7) return '信度可接受';
        if (alpha >= 0.6) return '信度勉强可接受';
        return '信度不佳';
    }
}

// 导出计算器
window.ReliabilityCalculator = ReliabilityCalculator;